{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f7299ebc",
   "metadata": {
    "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
    "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:34.687811Z",
     "iopub.status.busy": "2025-05-15T03:03:34.687479Z",
     "iopub.status.idle": "2025-05-15T03:03:39.610540Z",
     "shell.execute_reply": "2025-05-15T03:03:39.609635Z"
    },
    "papermill": {
     "duration": 4.929161,
     "end_time": "2025-05-15T03:03:39.612217",
     "exception": false,
     "start_time": "2025-05-15T03:03:34.683056",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m74.4/74.4 kB\u001b[0m \u001b[31m1.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n",
      "\u001b[?25h"
     ]
    }
   ],
   "source": [
    "!pip install tfts --quiet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5dee2154",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:39.619766Z",
     "iopub.status.busy": "2025-05-15T03:03:39.619464Z",
     "iopub.status.idle": "2025-05-15T03:03:59.513448Z",
     "shell.execute_reply": "2025-05-15T03:03:59.512453Z"
    },
    "papermill": {
     "duration": 19.899404,
     "end_time": "2025-05-15T03:03:59.515035",
     "exception": false,
     "start_time": "2025-05-15T03:03:39.615631",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-05-15 03:03:43.156887: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "E0000 00:00:1747278223.380152      19 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "E0000 00:00:1747278223.444042      19 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
      "I0000 00:00:1747278239.457192      19 gpu_device.cc:2022] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 15513 MB memory:  -> device: 0, name: Tesla P100-PCIE-16GB, pci bus id: 0000:00:04.0, compute capability: 6.0\n"
     ]
    }
   ],
   "source": [
    "import logging\n",
    "from typing import List, Optional, Union\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import tensorflow as tf\n",
    "\n",
    "from tfts import AutoConfig, AutoModel, KerasTrainer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "74dc1396",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:59.522269Z",
     "iopub.status.busy": "2025-05-15T03:03:59.521678Z",
     "iopub.status.idle": "2025-05-15T03:03:59.525891Z",
     "shell.execute_reply": "2025-05-15T03:03:59.525300Z"
    },
    "papermill": {
     "duration": 0.00906,
     "end_time": "2025-05-15T03:03:59.527186",
     "exception": false,
     "start_time": "2025-05-15T03:03:59.518126",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class CFG:\n",
    "    input_dir = \"/kaggle/input/china-vehicle-sales-data/china_vehicle_sales_data.csv\"\n",
    "    train_sequence_length = 12\n",
    "    predict_sequence_length = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "0b799ee4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:59.533638Z",
     "iopub.status.busy": "2025-05-15T03:03:59.533407Z",
     "iopub.status.idle": "2025-05-15T03:03:59.648999Z",
     "shell.execute_reply": "2025-05-15T03:03:59.648165Z"
    },
    "papermill": {
     "duration": 0.12041,
     "end_time": "2025-05-15T03:03:59.650457",
     "exception": false,
     "start_time": "2025-05-15T03:03:59.530047",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Date</th>\n",
       "      <th>province</th>\n",
       "      <th>provinceId</th>\n",
       "      <th>popularity</th>\n",
       "      <th>model</th>\n",
       "      <th>bodyType</th>\n",
       "      <th>salesVolume</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>201601</td>\n",
       "      <td>Shanghai</td>\n",
       "      <td>310000</td>\n",
       "      <td>1479</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>292</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>201601</td>\n",
       "      <td>Yunnan</td>\n",
       "      <td>530000</td>\n",
       "      <td>1594</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>466</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>201601</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>1479</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>257</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>201601</td>\n",
       "      <td>Beijing</td>\n",
       "      <td>110000</td>\n",
       "      <td>2370</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>408</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>201601</td>\n",
       "      <td>Sichuan</td>\n",
       "      <td>510000</td>\n",
       "      <td>3562</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>610</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43291</th>\n",
       "      <td>201708</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>9716</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>58</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43292</th>\n",
       "      <td>201709</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>9128</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>74</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43293</th>\n",
       "      <td>201710</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>8700</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>48</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43294</th>\n",
       "      <td>201711</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>7284</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>48</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43295</th>\n",
       "      <td>201712</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>7376</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>57</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>43296 rows × 7 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "         Date        province  provinceId  popularity             model  \\\n",
       "0      201601        Shanghai      310000        1479  3c974920a76ac9c1   \n",
       "1      201601          Yunnan      530000        1594  3c974920a76ac9c1   \n",
       "2      201601  Inner Mongolia      150000        1479  3c974920a76ac9c1   \n",
       "3      201601         Beijing      110000        2370  3c974920a76ac9c1   \n",
       "4      201601         Sichuan      510000        3562  3c974920a76ac9c1   \n",
       "...       ...             ...         ...         ...               ...   \n",
       "43291  201708  Inner Mongolia      150000        9716  32d3069d17aa47c2   \n",
       "43292  201709  Inner Mongolia      150000        9128  32d3069d17aa47c2   \n",
       "43293  201710  Inner Mongolia      150000        8700  32d3069d17aa47c2   \n",
       "43294  201711  Inner Mongolia      150000        7284  32d3069d17aa47c2   \n",
       "43295  201712  Inner Mongolia      150000        7376  32d3069d17aa47c2   \n",
       "\n",
       "      bodyType  salesVolume  \n",
       "0          SUV          292  \n",
       "1          SUV          466  \n",
       "2          SUV          257  \n",
       "3          SUV          408  \n",
       "4          SUV          610  \n",
       "...        ...          ...  \n",
       "43291      MPV           58  \n",
       "43292      MPV           74  \n",
       "43293      MPV           48  \n",
       "43294      MPV           48  \n",
       "43295      MPV           57  \n",
       "\n",
       "[43296 rows x 7 columns]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_csv(CFG.input_dir)\n",
    "\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ad6327cc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:59.657856Z",
     "iopub.status.busy": "2025-05-15T03:03:59.657148Z",
     "iopub.status.idle": "2025-05-15T03:03:59.663920Z",
     "shell.execute_reply": "2025-05-15T03:03:59.663102Z"
    },
    "papermill": {
     "duration": 0.01178,
     "end_time": "2025-05-15T03:03:59.665360",
     "exception": false,
     "start_time": "2025-05-15T03:03:59.653580",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# https://github.com/hongyingyue/Vehicle-sales-predictor/blob/main/vehicle_ml/feature/ts_feature.py\n",
    "\n",
    "logger = logging.getLogger(__name__)\n",
    "\n",
    "\n",
    "def add_lagging_feature(\n",
    "    data: pd.DataFrame,\n",
    "    groupby_column: Union[str, List[str]],\n",
    "    value_columns: List[str],\n",
    "    lags: List[int],\n",
    "    feature_columns: Optional[List[str]] = None,\n",
    "):\n",
    "    # note that the data should be sorted by time already\n",
    "    # the lagging feature could be further developed use f1 - f1_lag, or f1 / f1_lag\n",
    "\n",
    "    if not isinstance(groupby_column, (str, list)):\n",
    "        raise TypeError(f\"'groupby_column' must be a string or a list of strings, but got {type(groupby_column)}.\")\n",
    "\n",
    "    if not isinstance(value_columns, (list, tuple)):\n",
    "        raise TypeError(f\"'value_columns' must be a list of strings, but got {type(value_columns)}.\")\n",
    "\n",
    "    feature_columns: List[str] = feature_columns if feature_columns is not None else []\n",
    "    for column in value_columns:\n",
    "        if column not in data.columns:\n",
    "            raise ValueError(f\"Value column '{column}' not found in DataFrame.\")\n",
    "\n",
    "        for lag in lags:\n",
    "            feature_col_name = f\"{column}_lag{lag}\"\n",
    "            feature_columns.append(feature_col_name)\n",
    "            data[feature_col_name] = data.groupby(groupby_column)[column].shift(lag)\n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "59cf3ced",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:59.672553Z",
     "iopub.status.busy": "2025-05-15T03:03:59.672297Z",
     "iopub.status.idle": "2025-05-15T03:03:59.776311Z",
     "shell.execute_reply": "2025-05-15T03:03:59.775181Z"
    },
    "papermill": {
     "duration": 0.109114,
     "end_time": "2025-05-15T03:03:59.777726",
     "exception": false,
     "start_time": "2025-05-15T03:03:59.668612",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.11/dist-packages/pandas/io/formats/format.py:1458: RuntimeWarning: invalid value encountered in greater\n",
      "  has_large_values = (abs_vals > 1e6).any()\n",
      "/usr/local/lib/python3.11/dist-packages/pandas/io/formats/format.py:1459: RuntimeWarning: invalid value encountered in less\n",
      "  has_small_values = ((abs_vals < 10 ** (-self.digits)) & (abs_vals > 0)).any()\n",
      "/usr/local/lib/python3.11/dist-packages/pandas/io/formats/format.py:1459: RuntimeWarning: invalid value encountered in greater\n",
      "  has_small_values = ((abs_vals < 10 ** (-self.digits)) & (abs_vals > 0)).any()\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Date</th>\n",
       "      <th>province</th>\n",
       "      <th>provinceId</th>\n",
       "      <th>popularity</th>\n",
       "      <th>model</th>\n",
       "      <th>bodyType</th>\n",
       "      <th>salesVolume</th>\n",
       "      <th>salesVolume_lag1</th>\n",
       "      <th>salesVolume_lag2</th>\n",
       "      <th>salesVolume_lag3</th>\n",
       "      <th>salesVolume_lag4</th>\n",
       "      <th>salesVolume_lag5</th>\n",
       "      <th>salesVolume_lag6</th>\n",
       "      <th>salesVolume_lag7</th>\n",
       "      <th>salesVolume_lag8</th>\n",
       "      <th>salesVolume_lag9</th>\n",
       "      <th>salesVolume_lag10</th>\n",
       "      <th>salesVolume_lag11</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>201601</td>\n",
       "      <td>Shanghai</td>\n",
       "      <td>310000</td>\n",
       "      <td>1479</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>292</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>201601</td>\n",
       "      <td>Yunnan</td>\n",
       "      <td>530000</td>\n",
       "      <td>1594</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>466</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>201601</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>1479</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>257</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>201601</td>\n",
       "      <td>Beijing</td>\n",
       "      <td>110000</td>\n",
       "      <td>2370</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>408</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>201601</td>\n",
       "      <td>Sichuan</td>\n",
       "      <td>510000</td>\n",
       "      <td>3562</td>\n",
       "      <td>3c974920a76ac9c1</td>\n",
       "      <td>SUV</td>\n",
       "      <td>610</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43291</th>\n",
       "      <td>201708</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>9716</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>58</td>\n",
       "      <td>67.0</td>\n",
       "      <td>62.0</td>\n",
       "      <td>36.0</td>\n",
       "      <td>35.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>55.0</td>\n",
       "      <td>44.0</td>\n",
       "      <td>39.0</td>\n",
       "      <td>40.0</td>\n",
       "      <td>47.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43292</th>\n",
       "      <td>201709</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>9128</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>74</td>\n",
       "      <td>58.0</td>\n",
       "      <td>67.0</td>\n",
       "      <td>62.0</td>\n",
       "      <td>36.0</td>\n",
       "      <td>35.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>55.0</td>\n",
       "      <td>44.0</td>\n",
       "      <td>39.0</td>\n",
       "      <td>40.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43293</th>\n",
       "      <td>201710</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>8700</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>48</td>\n",
       "      <td>74.0</td>\n",
       "      <td>58.0</td>\n",
       "      <td>67.0</td>\n",
       "      <td>62.0</td>\n",
       "      <td>36.0</td>\n",
       "      <td>35.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>55.0</td>\n",
       "      <td>44.0</td>\n",
       "      <td>39.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43294</th>\n",
       "      <td>201711</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>7284</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>48</td>\n",
       "      <td>48.0</td>\n",
       "      <td>74.0</td>\n",
       "      <td>58.0</td>\n",
       "      <td>67.0</td>\n",
       "      <td>62.0</td>\n",
       "      <td>36.0</td>\n",
       "      <td>35.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>55.0</td>\n",
       "      <td>44.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43295</th>\n",
       "      <td>201712</td>\n",
       "      <td>Inner Mongolia</td>\n",
       "      <td>150000</td>\n",
       "      <td>7376</td>\n",
       "      <td>32d3069d17aa47c2</td>\n",
       "      <td>MPV</td>\n",
       "      <td>57</td>\n",
       "      <td>48.0</td>\n",
       "      <td>48.0</td>\n",
       "      <td>74.0</td>\n",
       "      <td>58.0</td>\n",
       "      <td>67.0</td>\n",
       "      <td>62.0</td>\n",
       "      <td>36.0</td>\n",
       "      <td>35.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>55.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>43296 rows × 18 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "         Date        province  provinceId  popularity             model  \\\n",
       "0      201601        Shanghai      310000        1479  3c974920a76ac9c1   \n",
       "1      201601          Yunnan      530000        1594  3c974920a76ac9c1   \n",
       "2      201601  Inner Mongolia      150000        1479  3c974920a76ac9c1   \n",
       "3      201601         Beijing      110000        2370  3c974920a76ac9c1   \n",
       "4      201601         Sichuan      510000        3562  3c974920a76ac9c1   \n",
       "...       ...             ...         ...         ...               ...   \n",
       "43291  201708  Inner Mongolia      150000        9716  32d3069d17aa47c2   \n",
       "43292  201709  Inner Mongolia      150000        9128  32d3069d17aa47c2   \n",
       "43293  201710  Inner Mongolia      150000        8700  32d3069d17aa47c2   \n",
       "43294  201711  Inner Mongolia      150000        7284  32d3069d17aa47c2   \n",
       "43295  201712  Inner Mongolia      150000        7376  32d3069d17aa47c2   \n",
       "\n",
       "      bodyType  salesVolume  salesVolume_lag1  salesVolume_lag2  \\\n",
       "0          SUV          292               NaN               NaN   \n",
       "1          SUV          466               NaN               NaN   \n",
       "2          SUV          257               NaN               NaN   \n",
       "3          SUV          408               NaN               NaN   \n",
       "4          SUV          610               NaN               NaN   \n",
       "...        ...          ...               ...               ...   \n",
       "43291      MPV           58              67.0              62.0   \n",
       "43292      MPV           74              58.0              67.0   \n",
       "43293      MPV           48              74.0              58.0   \n",
       "43294      MPV           48              48.0              74.0   \n",
       "43295      MPV           57              48.0              48.0   \n",
       "\n",
       "       salesVolume_lag3  salesVolume_lag4  salesVolume_lag5  salesVolume_lag6  \\\n",
       "0                   NaN               NaN               NaN               NaN   \n",
       "1                   NaN               NaN               NaN               NaN   \n",
       "2                   NaN               NaN               NaN               NaN   \n",
       "3                   NaN               NaN               NaN               NaN   \n",
       "4                   NaN               NaN               NaN               NaN   \n",
       "...                 ...               ...               ...               ...   \n",
       "43291              36.0              35.0              54.0              31.0   \n",
       "43292              62.0              36.0              35.0              54.0   \n",
       "43293              67.0              62.0              36.0              35.0   \n",
       "43294              58.0              67.0              62.0              36.0   \n",
       "43295              74.0              58.0              67.0              62.0   \n",
       "\n",
       "       salesVolume_lag7  salesVolume_lag8  salesVolume_lag9  \\\n",
       "0                   NaN               NaN               NaN   \n",
       "1                   NaN               NaN               NaN   \n",
       "2                   NaN               NaN               NaN   \n",
       "3                   NaN               NaN               NaN   \n",
       "4                   NaN               NaN               NaN   \n",
       "...                 ...               ...               ...   \n",
       "43291              55.0              44.0              39.0   \n",
       "43292              31.0              55.0              44.0   \n",
       "43293              54.0              31.0              55.0   \n",
       "43294              35.0              54.0              31.0   \n",
       "43295              36.0              35.0              54.0   \n",
       "\n",
       "       salesVolume_lag10  salesVolume_lag11  \n",
       "0                    NaN                NaN  \n",
       "1                    NaN                NaN  \n",
       "2                    NaN                NaN  \n",
       "3                    NaN                NaN  \n",
       "4                    NaN                NaN  \n",
       "...                  ...                ...  \n",
       "43291               40.0               47.0  \n",
       "43292               39.0               40.0  \n",
       "43293               44.0               39.0  \n",
       "43294               55.0               44.0  \n",
       "43295               31.0               55.0  \n",
       "\n",
       "[43296 rows x 18 columns]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "feature_columns = []\n",
    "\n",
    "data = add_lagging_feature(\n",
    "    data,\n",
    "    groupby_column=[\"provinceId\", \"model\"],\n",
    "    value_columns=[\"salesVolume\"],\n",
    "    lags=list(range(1, 12)),\n",
    "    feature_columns=feature_columns,\n",
    ")\n",
    "\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "709bf16a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:03:59.785639Z",
     "iopub.status.busy": "2025-05-15T03:03:59.785345Z",
     "iopub.status.idle": "2025-05-15T03:04:01.362728Z",
     "shell.execute_reply": "2025-05-15T03:04:01.361830Z"
    },
    "papermill": {
     "duration": 1.582827,
     "end_time": "2025-05-15T03:04:01.364162",
     "exception": false,
     "start_time": "2025-05-15T03:03:59.781335",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_19/3102104721.py:1: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
      "  grouped_sequence = data.groupby([\"provinceId\", \"model\"]).apply(\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[[ 799.,   nan,   nan,   nan],\n",
       "        [ 424.,  799.,   nan,   nan],\n",
       "        [ 733.,  424.,  799.,   nan],\n",
       "        ...,\n",
       "        [ 544.,  659.,  630.,  670.],\n",
       "        [ 647.,  544.,  659.,  630.],\n",
       "        [ 640.,  647.,  544.,  659.]],\n",
       "\n",
       "       [[ 135.,   nan,   nan,   nan],\n",
       "        [  57.,  135.,   nan,   nan],\n",
       "        [ 160.,   57.,  135.,   nan],\n",
       "        ...,\n",
       "        [ 105.,  201.,  120.,  135.],\n",
       "        [ 148.,  105.,  201.,  120.],\n",
       "        [ 112.,  148.,  105.,  201.]],\n",
       "\n",
       "       [[ 872.,   nan,   nan,   nan],\n",
       "        [ 197.,  872.,   nan,   nan],\n",
       "        [ 494.,  197.,  872.,   nan],\n",
       "        ...,\n",
       "        [ 152.,  170.,  181.,  159.],\n",
       "        [ 213.,  152.,  170.,  181.],\n",
       "        [ 226.,  213.,  152.,  170.]],\n",
       "\n",
       "       ...,\n",
       "\n",
       "       [[ 181.,   nan,   nan,   nan],\n",
       "        [  60.,  181.,   nan,   nan],\n",
       "        [ 111.,   60.,  181.,   nan],\n",
       "        ...,\n",
       "        [ 330.,  297.,  252.,  199.],\n",
       "        [ 178.,  330.,  297.,  252.],\n",
       "        [ 185.,  178.,  330.,  297.]],\n",
       "\n",
       "       [[1023.,   nan,   nan,   nan],\n",
       "        [ 517., 1023.,   nan,   nan],\n",
       "        [ 513.,  517., 1023.,   nan],\n",
       "        ...,\n",
       "        [1110.,  991.,  975.,  798.],\n",
       "        [ 967., 1110.,  991.,  975.],\n",
       "        [1581.,  967., 1110.,  991.]],\n",
       "\n",
       "       [[ 170.,   nan,   nan,   nan],\n",
       "        [  37.,  170.,   nan,   nan],\n",
       "        [ 124.,   37.,  170.,   nan],\n",
       "        ...,\n",
       "        [ 229.,  236.,  208.,  749.],\n",
       "        [ 240.,  229.,  236.,  208.],\n",
       "        [ 337.,  240.,  229.,  236.]]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_sequence = data.groupby([\"provinceId\", \"model\"]).apply(\n",
    "    lambda x: x.sort_values(\"Date\")[\n",
    "        [\"salesVolume\", \"salesVolume_lag1\", \"salesVolume_lag2\", \"salesVolume_lag3\"]\n",
    "    ].to_numpy()\n",
    ")\n",
    "\n",
    "data_3d = np.stack(grouped_sequence.values)\n",
    "\n",
    "data_3d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2f153615",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:04:01.373679Z",
     "iopub.status.busy": "2025-05-15T03:04:01.372595Z",
     "iopub.status.idle": "2025-05-15T03:04:01.383825Z",
     "shell.execute_reply": "2025-05-15T03:04:01.383203Z"
    },
    "papermill": {
     "duration": 0.017129,
     "end_time": "2025-05-15T03:04:01.385181",
     "exception": false,
     "start_time": "2025-05-15T03:04:01.368052",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.utils import Sequence\n",
    "\n",
    "\n",
    "class TimeDataset(Sequence):\n",
    "    def __init__(self, data, train_sequence_length, predict_sequence_length, batch_size: int = 64):\n",
    "        self.data = data\n",
    "        self.train_seq_len = train_sequence_length\n",
    "        self.pred_seq_len = predict_sequence_length\n",
    "        self.batch_size = batch_size\n",
    "\n",
    "        self.num_ids = data.shape[0]\n",
    "        self.max_seq_len = data.shape[1]\n",
    "        self.feature_dim = data.shape[2]\n",
    "\n",
    "        self.samples_per_id = self.max_seq_len - self.train_seq_len - self.pred_seq_len + 1\n",
    "        self.total_samples = self.num_ids * self.samples_per_id\n",
    "\n",
    "        # Precompute all valid (id, start_idx) pairs\n",
    "        self.indices = [(i, j) for i in range(self.num_ids) for j in range(self.samples_per_id)]\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        # batch-wise item\n",
    "        batch_indices = self.indices[index * self.batch_size : (index + 1) * self.batch_size]\n",
    "\n",
    "        x_batch = []\n",
    "        y_batch = []\n",
    "\n",
    "        for id_idx, start_idx in batch_indices:\n",
    "            x = self.data[id_idx, start_idx : start_idx + self.train_seq_len, 1:]\n",
    "            y = self.data[\n",
    "                id_idx, start_idx + self.train_seq_len : start_idx + self.train_seq_len + self.pred_seq_len, 0\n",
    "            ]\n",
    "            x_batch.append(x)\n",
    "            y_batch.append(y)\n",
    "\n",
    "        return np.nan_to_num(np.array(x_batch)), np.nan_to_num(np.array(y_batch))\n",
    "\n",
    "    def __len__(self):\n",
    "        # depends on how many samples you want to extract from 1 ID\n",
    "        return int(np.ceil(len(self.indices) / self.batch_size))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "95ccaa23",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:04:01.394289Z",
     "iopub.status.busy": "2025-05-15T03:04:01.393689Z",
     "iopub.status.idle": "2025-05-15T03:04:01.405207Z",
     "shell.execute_reply": "2025-05-15T03:04:01.404312Z"
    },
    "papermill": {
     "duration": 0.017307,
     "end_time": "2025-05-15T03:04:01.406674",
     "exception": false,
     "start_time": "2025-05-15T03:04:01.389367",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(64, 12, 3)\n",
      "(64, 3)\n"
     ]
    }
   ],
   "source": [
    "train_dataset = TimeDataset(data_3d, CFG.train_sequence_length, CFG.predict_sequence_length)\n",
    "valid_dataset = TimeDataset(data_3d, CFG.train_sequence_length, CFG.predict_sequence_length)\n",
    "\n",
    "print(train_dataset[0][0].shape)\n",
    "print(train_dataset[0][1].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d7ab6b8a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:04:01.415881Z",
     "iopub.status.busy": "2025-05-15T03:04:01.415372Z",
     "iopub.status.idle": "2025-05-15T03:04:02.926120Z",
     "shell.execute_reply": "2025-05-15T03:04:02.925158Z"
    },
    "papermill": {
     "duration": 1.516548,
     "end_time": "2025-05-15T03:04:02.927422",
     "exception": false,
     "start_time": "2025-05-15T03:04:01.410874",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"functional\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"functional\"\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Layer (type)                         </span>┃<span style=\"font-weight: bold\"> Output Shape                </span>┃<span style=\"font-weight: bold\">         Param # </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩\n",
       "│ input_layer (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)             │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">12</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>)               │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ encoder (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Encoder</span>)                    │ [(<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">12</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>), (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>,     │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "│                                      │ <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>)]                       │                 │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                        │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>)                 │          <span style=\"color: #00af00; text-decoration-color: #00af00\">16,512</span> │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                      │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>)                 │          <span style=\"color: #00af00; text-decoration-color: #00af00\">16,512</span> │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                      │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1</span>)                   │             <span style=\"color: #00af00; text-decoration-color: #00af00\">129</span> │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ reshape (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Reshape</span>)                    │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1</span>)                │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                        \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape               \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m        Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩\n",
       "│ input_layer (\u001b[38;5;33mInputLayer\u001b[0m)             │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m3\u001b[0m)               │               \u001b[38;5;34m0\u001b[0m │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ encoder (\u001b[38;5;33mEncoder\u001b[0m)                    │ [(\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m64\u001b[0m), (\u001b[38;5;45mNone\u001b[0m,     │               \u001b[38;5;34m0\u001b[0m │\n",
       "│                                      │ \u001b[38;5;34m128\u001b[0m)]                       │                 │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense (\u001b[38;5;33mDense\u001b[0m)                        │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m)                 │          \u001b[38;5;34m16,512\u001b[0m │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense_1 (\u001b[38;5;33mDense\u001b[0m)                      │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m)                 │          \u001b[38;5;34m16,512\u001b[0m │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ dense_2 (\u001b[38;5;33mDense\u001b[0m)                      │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m)                   │             \u001b[38;5;34m129\u001b[0m │\n",
       "├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤\n",
       "│ reshape (\u001b[38;5;33mReshape\u001b[0m)                    │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m, \u001b[38;5;34m1\u001b[0m)                │               \u001b[38;5;34m0\u001b[0m │\n",
       "└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">33,153</span> (129.50 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m33,153\u001b[0m (129.50 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">33,153</span> (129.50 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m33,153\u001b[0m (129.50 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def build_model():\n",
    "    inputs = tf.keras.Input(shape=(CFG.train_sequence_length, 3))\n",
    "\n",
    "    config = AutoConfig()(\"rnn\")\n",
    "    config.rnn_type = \"lstm\"\n",
    "    backbone = AutoModel.from_config(config=config)\n",
    "\n",
    "    outputs = backbone(inputs)\n",
    "    model = tf.keras.Model(inputs=inputs, outputs=outputs)\n",
    "    model.compile(loss=tf.keras.losses.MeanAbsoluteError(), optimizer=tf.keras.optimizers.Adam(), metrics=[\"mae\"])\n",
    "    return model\n",
    "\n",
    "\n",
    "model = build_model()\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "66f3afd8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-05-15T03:04:02.937555Z",
     "iopub.status.busy": "2025-05-15T03:04:02.936632Z",
     "iopub.status.idle": "2025-05-15T03:04:35.886543Z",
     "shell.execute_reply": "2025-05-15T03:04:35.885756Z"
    },
    "papermill": {
     "duration": 32.956278,
     "end_time": "2025-05-15T03:04:35.888099",
     "exception": false,
     "start_time": "2025-05-15T03:04:02.931821",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.11/dist-packages/keras/src/trainers/data_adapters/py_dataset_adapter.py:121: UserWarning: Your `PyDataset` class should call `super().__init__(**kwargs)` in its constructor. `**kwargs` can include `workers`, `use_multiprocessing`, `max_queue_size`. Do not pass these arguments to `fit()`, as they will be ignored.\n",
      "  self._warn_if_super_not_called()\n",
      "I0000 00:00:1747278246.661268      65 cuda_dnn.cc:529] Loaded cuDNN version 90300\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 11ms/step - loss: 350.8878 - mae: 350.8878 - val_loss: 182.2173 - val_mae: 182.2173\n",
      "Epoch 2/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 170.9699 - mae: 170.9699 - val_loss: 173.9711 - val_mae: 173.9711\n",
      "Epoch 3/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 177.6421 - mae: 177.6421 - val_loss: 151.1356 - val_mae: 151.1356\n",
      "Epoch 4/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 167.8778 - mae: 167.8778 - val_loss: 181.6729 - val_mae: 181.6729\n",
      "Epoch 5/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 200.4965 - mae: 200.4965 - val_loss: 161.8659 - val_mae: 161.8659\n",
      "Epoch 6/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 11ms/step - loss: 159.5687 - mae: 159.5687 - val_loss: 203.8276 - val_mae: 203.8276\n",
      "Epoch 7/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 191.8186 - mae: 191.8186 - val_loss: 168.8145 - val_mae: 168.8145\n",
      "Epoch 8/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 154.9041 - mae: 154.9041 - val_loss: 148.9643 - val_mae: 148.9643\n",
      "Epoch 9/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 164.3612 - mae: 164.3612 - val_loss: 205.0088 - val_mae: 205.0088\n",
      "Epoch 10/10\n",
      "\u001b[1m282/282\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 10ms/step - loss: 157.4605 - mae: 157.4605 - val_loss: 216.5961 - val_mae: 216.5961\n"
     ]
    }
   ],
   "source": [
    "history = model.fit(train_dataset, validation_data=valid_dataset, epochs=10)\n",
    "model.save_weights(\"./sales_model.weights.h5\")"
   ]
  }
 ],
 "metadata": {
  "kaggle": {
   "accelerator": "gpu",
   "dataSources": [
    {
     "datasetId": 7421883,
     "sourceId": 11816396,
     "sourceType": "datasetVersion"
    }
   ],
   "dockerImageVersionId": 31041,
   "isGpuEnabled": true,
   "isInternetEnabled": true,
   "language": "python",
   "sourceType": "notebook"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 69.520885,
   "end_time": "2025-05-15T03:04:39.263217",
   "environment_variables": {},
   "exception": null,
   "input_path": "__notebook__.ipynb",
   "output_path": "__notebook__.ipynb",
   "parameters": {},
   "start_time": "2025-05-15T03:03:29.742332",
   "version": "2.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
